import type { ResultBean, Bean, ResultBeanAsObject } from '../../interface';
import { removeEmptyFields } from '../transData';
import { Request } from './axios';
import type { AxiosRequestConfig } from 'axios';
import {
  calcPageInfoResult,
  calcBackServerPageInfoParams,
  enumFrontPageInfoKey,
} from '../transPageInfo';

const requestIns = new Request({ baseURL: '/' });

export function setBaseURL(url: string) {
  const { baseConfig } = requestIns;
  requestIns.baseConfig = { ...baseConfig, baseURL: url };
}

type RequestMethod =
  | 'get'
  | 'options'
  | 'head'
  | 'post'
  | 'put'
  | 'delete'
  | 'trace'
  | 'connect'
  | undefined;

export interface RequestConfig {
  clearEmptyFields?: boolean;
  useDvaCommonError?: boolean;
  failMsg?: string;
  method?: RequestMethod;
}

export function isContainPageKey(obj: any): boolean {
  if (!obj) {
    return false;
  }
  const keys = Object.keys(obj);
  if (
    keys.includes(enumFrontPageInfoKey.pageSize) &&
    keys.includes(enumFrontPageInfoKey.current)
  ) {
    return true;
  }
  return false;
}

export async function baseRequest<T>(
  url: string,
  options: AxiosRequestConfig,
  otherConfig: RequestConfig,
) {
  const hasQueryPageKey = isContainPageKey(options.params);
  const hasBodyPageKey = isContainPageKey(options.data);
  const { ...otherOptions } = options;
  otherOptions.url = url;
  if (hasBodyPageKey) {
    otherOptions.data = calcBackServerPageInfoParams(options.data);
  }
  if (hasQueryPageKey) {
    otherOptions.params = calcBackServerPageInfoParams(options.params as Bean);
  }

  const { failMsg = '', useDvaCommonError = true } = otherConfig;
  const response = await requestIns.request<T>(otherOptions);
  const { data } = response;
  const result = data as ResultBean<T>;
  const success = response.status === 200;
  if (!success && useDvaCommonError) {
    throw new Error(`${failMsg}~${result.message}`);
  }
  if (hasQueryPageKey || hasBodyPageKey) {
    return calcPageInfoResult(result);
  }
  return result;
}

function post<T = ResultBeanAsObject>(
  url: string,
  params: Bean,
  otherConfig: RequestConfig = {},
) {
  let newParams = params;
  const { clearEmptyFields = false, method = 'POST' } = otherConfig;
  if (clearEmptyFields) {
    newParams = removeEmptyFields(params);
  }
  return baseRequest<T>(
    url,
    {
      method,
      data: newParams,
    },
    otherConfig,
  );
}

function get<T = ResultBeanAsObject>(
  url: string,
  params: Bean,
  otherConfig: RequestConfig = {},
) {
  let newParams = params;
  const { clearEmptyFields = false, method = 'GET' } = otherConfig;
  if (clearEmptyFields) {
    newParams = removeEmptyFields(params);
  }
  return baseRequest<T>(
    url,
    {
      method,
      params: newParams,
    },
    otherConfig,
  );
}

// 默认导出Request实例
export default {
  post,
  get,
  baseRequest,
};
